using System;
using System.Collections.Generic;
using Arena;
using MenuTeste;

namespace TAC {

	class Facil : InteligenciaArtificial {
		public readonly NPC controlado;
		private List<ListaAtacantes> listaAtacantes;
		private Arena.MapaReal mapa;
		private int alvo;
		
		public Facil (ref NPC control, ref Arena.MapaReal map) {
			controlado = control;
			listaAtacantes = new List<ListaAtacantes> ();
			mapa = map;
			alvo = 0;
		}
		
		/* FUNCOES */
		
		private static int comparaLista (ListaAtacantes um, ListaAtacantes dois) {
			if (um.personagem().isDead()) {
				if (dois.personagem().isDead()) {
					return 0;
				} else {
					return -1;
				}
			} else {
				if (dois.personagem().isDead()) {
					return 1;
				} else {
					int tmp = um.ataques() - dois.ataques();
					
					if (tmp != 0) {
						return tmp;
					} else {
						int tmp2 = (um.personagem().getAttribute(ID.HEALTH) - um.personagem().getAttribute(ID.DAMAGE)) - (dois.personagem().getAttribute(ID.HEALTH) - dois.personagem().getAttribute(ID.DAMAGE));
						
						if (tmp2 != 0) {
							return tmp2;
						} else {
							int tmp3 = um.personagem().getAttribute(ID.TOTAL_POINTS) - dois.personagem().getAttribute(ID.TOTAL_POINTS);
							
							if (tmp3 != 0) {
								return tmp3;
							} else {
								int tmp4 = um.personagem().getAttribute(ID.EXPERIENCE) - dois.personagem().getAttribute(ID.EXPERIENCE);
								return (tmp4 > 0) ? 1 : ((tmp4 < 0) ? -1 : 0);
							}
						}
					}
				}
			}
			
		}
		
		private void aoSerAtacado () {
			bool contido = false;
			int i;
			
			for (i = 0; i < listaAtacantes.Count; i++) {
				if (listaAtacantes[i].personagem() == controlado.character.getAttackedBy()) {
					contido = true;
					break;
				}
			}
			
			if (!contido) {
				listaAtacantes.Add (new ListaAtacantes (controlado.character.getAttackedBy()));
			} else {
				listaAtacantes[i].aumentaAtaque();
			}
			
			ListaAtacantes alvoX = listaAtacantes[alvo];
			
			listaAtacantes.Sort(comparaLista);
			
			alvo = listaAtacantes.BinarySearch(alvoX);
		}
		
		/* ACOES */
		
		private void atacar (ref Character alvoX) {
			if (controlado.character.getAttribute(ID.DEXTERITY) >= controlado.character.getAttribute(ID.INTELLIGENCE)) {
				controlado.character.BasicAttack(ref alvoX);
                controlado.Atacked();
			} else {
				controlado.character.SpecialAttack(ref alvoX);
                controlado.SuperAttacked();
			}
            
		}
		
		private void perseguir (Character alvoX) {
			if (!mapa.adjacente(controlado.character, alvoX)) {
                double[] hipotenusas =
                            {
                                (mapa.pontoValido(controlado.character.getX() + 1, controlado.character.getY())) ? 
                                    Math.Sqrt(Math.Pow(Math.Abs(alvoX.getX() - controlado.character.getX() + 1), 2) + Math.Pow(Math.Abs(alvoX.getY() - controlado.character.getY()), 2))
                                    : float.MinValue,
                                (mapa.pontoValido(controlado.character.getX() - 1, controlado.character.getY())) ?
                                    Math.Sqrt(Math.Pow(Math.Abs(alvoX.getX() - controlado.character.getX() - 1), 2) + Math.Pow(Math.Abs(alvoX.getY() - controlado.character.getY()), 2))
                                    : float.MinValue,
                                (mapa.pontoValido(controlado.character.getX(), controlado.character.getY() + 1)) ?
                                    Math.Sqrt(Math.Pow(Math.Abs(alvoX.getX() - controlado.character.getX()), 2) + Math.Pow(Math.Abs(alvoX.getY() - controlado.character.getY() + 1), 2))
                                    : float.MinValue,
                                (mapa.pontoValido(controlado.character.getX(), controlado.character.getY() - 1)) ?
                                    Math.Sqrt(Math.Pow(Math.Abs(alvoX.getX() - controlado.character.getX()), 2) + Math.Pow(Math.Abs(alvoX.getY() - controlado.character.getY() - 1), 2))
                                    : float.MinValue
                            };

                int direcao = 0;
                double temp = 0;

                for (int i = 0; i < 3; i++)
                {
                    if (hipotenusas[i] > temp)
                    {
                        direcao = i;
                        temp = hipotenusas[i];
                    }
                }

                switch (direcao)
                {
                    case 0:
                            controlado.Move(controlado.character.getX() + 1, controlado.character.getY());
                            break;
                    case 1:
                            controlado.Move(controlado.character.getX() - 1, controlado.character.getY());
                            break;
                    case 2:
                            controlado.Move(controlado.character.getX(), controlado.character.getY() + 1);
                            break;
                    case 3:
                            controlado.Move(controlado.character.getX(), controlado.character.getY() - 1);
                            break;
                }
                
			} else {
				atacar (ref alvoX);
			}
		}
		
	
		/* COMPORTAMENTO */
		
		public void comportamento () {
			if (listaAtacantes.Count > 0) {
				if (!listaAtacantes[alvo].personagem().isDead()) {
					perseguir(listaAtacantes[alvo].personagem());
				} else {
					listaAtacantes.RemoveAt(alvo);
					alvo = 0;
					perseguir(listaAtacantes[alvo].personagem());
				}
			} else {
				Character maisProximo = null;
                int xis = mapa.getX();
                int ipsilon = mapa.getY();
                foreach (NonPlayerCharacter a in mapa.personagens)
                    if (a != controlado.character)
                        if (Math.Abs(a.getX() - controlado.character.getX()) < xis || Math.Abs(a.getY() - controlado.character.getY()) < ipsilon)
                        {
                            xis = Math.Abs(a.getX() - controlado.character.getX());
                            ipsilon = Math.Abs(a.getY() - controlado.character.getY());
                            maisProximo = a;
                        }

				perseguir (maisProximo);
				listaAtacantes.Add (new ListaAtacantes (maisProximo));
			}
		}
		
	}
}
